package pi.client.board;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Iterator;

public class AEstrela {
	private Cell[][] mapa;
	private int mapaLargura=10;
	private int mapaAltura=8;
	
	private ArrayList<Nodo> aberto;
	private ArrayList<Nodo> fechado;
	private Point inicio;
	private Point fim;
	
	public AEstrela(Point inicio, Point fim, Cell[][] mapa) {
		this.inicio = inicio;
		this.fim = fim;
		this.mapa = mapa;
		aberto = new ArrayList<Nodo>();
		fechado = new ArrayList<Nodo>();
	}
	
	public ArrayList<Point> CalculaCaminho(){
		aberto.clear();
		fechado.clear();
		
		Nodo nodoAtual = new Nodo(null, inicio, mapa[(int) inicio.getX()][(int) inicio.getY()].costToWalk+Manhattan(inicio,fim));
		
		while(true){
			if(nodoAtual==null){
				break;
			}
			fechado.add(nodoAtual);
			
			Nodo nodosAdj[] = new Nodo[4];
			
			Point direita = new Point((int) nodoAtual.posicao.getX()+1, (int) nodoAtual.posicao.getY());
			Point esquerda = new Point((int) nodoAtual.posicao.getX()-1, (int) nodoAtual.posicao.getY());
			Point cima = new Point((int) nodoAtual.posicao.getX(), (int) nodoAtual.posicao.getY()-1);
			Point baixo = new Point((int) nodoAtual.posicao.getX(), (int) nodoAtual.posicao.getY()+1);
			
			nodosAdj[0] = expandirNodo(direita, nodoAtual);
			nodosAdj[1] = expandirNodo(esquerda, nodoAtual);
			nodosAdj[2] = expandirNodo(cima, nodoAtual);
			nodosAdj[3] = expandirNodo(baixo, nodoAtual);
			
			for(int i=0; i<4; i++){
				if(nodosAdj[i]!=null){
					if(nodosAdj[i].posicao.equals(fim)){
						return caminho(nodosAdj[i]);
					}
				}
			}
			
			
			int menorfuncao = 9999;
			Nodo nodoProximo = null;
			
			Iterator<Nodo> it =  aberto.iterator();
			while(it.hasNext()){
				Nodo nodoTeste = it.next();
				if(nodoTeste.custo <= menorfuncao){
					menorfuncao = nodoTeste.custo;
					nodoProximo = nodoTeste;
				}else if(nodoTeste.custo>=menorfuncao){
					if(nodoTeste.custo<nodoProximo.custo){
						menorfuncao = nodoTeste.custo;
						nodoProximo = nodoTeste;
					}
				}
			}
			
			if(nodoProximo == null){
				return null;
			}
			
			nodoAtual = nodoProximo;
			
			aberto.remove(nodoAtual);
		}
		return null;
	}
	
	public ArrayList<Point> caminho(Nodo nodo){
		ArrayList<Point> c = new ArrayList<Point>();
		Nodo it = nodo;
		c.add(it.posicao);
		while(it.pai!=null){
			it = it.pai;
			c.add(it.posicao);
		}
		
		return c;
	}

	private Nodo expandirNodo(Point posicao, Nodo pai){
		int x = (int) posicao.getX();
		int y = (int) posicao.getY();
		if(x>=0 && y>=0 && x<mapaLargura && y<mapaAltura){
			if(mapa[x][y].costToWalk<=2000 && mapa[x][y].unit==null){
				// Se nao esta na lista aberto
				Iterator<Nodo> it = aberto.iterator();
				while(it.hasNext()){
					Nodo teste = it.next();
					if(teste.posicao.getX()==x && teste.posicao.getY()==y){ //comparando int com double
						return null;
					}
				}
				
				// Se nao esta na lista fechado
				it = fechado.iterator();
				while(it.hasNext()){
					Nodo teste = it.next();
					if(teste.posicao.getX()==x && teste.posicao.getY()==y){ //comparando int com double
						return null;
					}
				}
				
				Nodo nodo = new Nodo(pai, posicao, mapa[x][y].costToWalk+Manhattan(posicao, fim));
				aberto.add(nodo);
				
				return nodo;
			}
		}
		return null;
	}

	public int Manhattan(Point inicio, Point fim){
		return (int) (Math.abs(inicio.getX()-fim.getX())+Math.abs(inicio.getY()-fim.getY()));
	} 
}